#include "ThreadPoolTest.h"
#include "CBL_ThreadPool.h"
#include "CBL_AtomicOperations.h"
#include "CBL_Cpu.h"
#include <time.h>

class CTestJob
{
public:

	CTestJob() : m_pFinished(NULL) {}
    
	void SetHook(bool* _pFinished) { m_pFinished = _pFinished; }
    void Run()					   { *m_pFinished = true; }
    
private:

	bool* m_pFinished;
};


BEGIN_TEST_CASE_IMPLEMENTATION(CThreadPoolTest)

Cb::Cpu::CThreadPool& rThreadPool = Cb::Cpu::CThreadPool::CreateInstance();

int Test = 1;

Cb::Cpu::ThreadAtomicIncrement(Test);

CHECK(Test==2, "> Atomic increment test failed.")

Cb::Cpu::ThreadAtomicDecrement(Test);

CHECK(Test==1, "> Atomic decrement test failed.")

int OldTest = Cb::Cpu::ThreadAtomicCompareAndSwap(Test, 1, 4);

CHECK(OldTest==1 && Test==4, "> Atomic CAS test failed.")

const int NumTests = 100;

bool TestFinished[NumTests];
CTestJob Tests[NumTests];
Cb::CDelegate TestJob[NumTests];

for (int i=0; i<NumTests; ++i)
{
	TestFinished[i] = false;
    Tests[i].SetHook(&TestFinished[i]);
    TestJob[i] = Cb::CDelegate::Create<CTestJob, &CTestJob::Run>(&Tests[i]);
    
    rThreadPool.PushJob(TestJob[i]);
}

rThreadPool.Drain();

int NumFailed = 0;

for (int i=0; i<NumTests; ++i)
{
	if (!TestFinished[i]) ++NumFailed;
}

CHECK(NumFailed==0, "> ThreadPool job and run failed for " << NumFailed << " jobs.")

for (int i=0; i<NumTests; ++i)
{
	TestFinished[i] = false;
    Tests[i].SetHook(&TestFinished[i]);
    TestJob[i] = Cb::CDelegate::Create<CTestJob, &CTestJob::Run>(&Tests[i]);
    
    rThreadPool.PushJob(TestJob[i]);
    
    if (i == NumTests / 2)
    	rThreadPool.Pause();
}

rThreadPool.Resume();
rThreadPool.Drain();

NumFailed = 0;

for (int i=0; i<NumTests; ++i)
{
	if (!TestFinished[i]) ++NumFailed;
}

CHECK(NumFailed==0, "> ThreadPool pause test failed for " << NumFailed << " jobs.")

Cb::Cpu::CThreadPool::Release();

END_TEST_CASE_IMPLEMENTATION